//
// Created by 34753 on 2025/5/22.
//

#ifndef ZQ_MCBSP_H
#define ZQ_MCBSP_H
#include <zq_conf.h>

#include "zq_systick.h"

namespace zq
{
    namespace mcbsp
    {
        namespace regs
        {
            // McBSP 基地址: 0x2800 (TMS320C5509 McBSP0 外设地址)
            // 所有寄存器均为16位宽度，使用小端模式

            //----------------------------------
            // 数据寄存器组
            //----------------------------------
            DECLARE_MMR_REGISTER(drr2, 0x2800); // 数据接收寄存器2 (只读)
            DECLARE_MMR_REGISTER(drr1, 0x2801); // 数据接收寄存器1 (只读)
            DECLARE_MMR_REGISTER(dxr2, 0x2802); // 数据发送寄存器2 (只写)
            DECLARE_MMR_REGISTER(dxr1, 0x2803); // 数据发送寄存器1 (只写)

            //----------------------------------
            // 控制寄存器组
            //----------------------------------
            // 串口控制寄存器2
            BEGIN_MMR_REGISTER(spcr2, 0x2804)
                DECLARE_MMR_BIT(FREE, 9)             // [9] 自由运行模式
                DECLARE_MMR_BIT(SOFT, 8)             // [8] 软模式
                DECLARE_MMR_BIT(FRST, 7)             // [7] 帧同步发生器复位
                DECLARE_MMR_BIT(GRST, 6)             // [6] 采样率发生器复位
                DECLARE_MMR_BITS_FIELD(XINTM, 2, 4)  // [5-4] 发送中断模式
                DECLARE_MMR_BIT(XSYNCERR, 3)         // [3] 发送同步错误标志
                DECLARE_MMR_BIT(XEMPTY, 2)           // [2] 发送移位寄存器空标志
                DECLARE_MMR_BIT(XRDY, 1)             // [1] 发送就绪标志
                DECLARE_MMR_BIT(XRST, 0)             // [0] 发送器复位/使能
            END_MMR_REGISTER()

            // 串口控制寄存器1
            BEGIN_MMR_REGISTER(spcr1, 0x2805)
                DECLARE_MMR_BIT(DLB, 15)             // [15] 数字环回模式使能
                DECLARE_MMR_BITS_FIELD(RJUST, 2, 13) // [14-13] 接收数据对齐方式
                DECLARE_MMR_BITS_FIELD(CLKSTP, 2, 11) // [12-11] 时钟停止模式
                DECLARE_MMR_BIT(DXENA, 7)            // [7] DX引脚延时使能
                DECLARE_MMR_BIT(ABIS, 6)             // [6] ABIS模式使能
                DECLARE_MMR_BITS_FIELD(RINTM, 2, 4)  // [5-4] 接收中断模式
                DECLARE_MMR_BIT(RSYNCERR, 3)         // [3] 接收同步错误标志
                DECLARE_MMR_BIT(RFULL, 2)            // [2] 接收移位寄存器满标志
                DECLARE_MMR_BIT(RRDY, 1)             // [1] 接收就绪标志
                DECLARE_MMR_BIT(RRST, 0)             // [0] 接收器复位/使能
            END_MMR_REGISTER()


            //----------------------------------
            // 接收/发送配置寄存器
            //----------------------------------
            /* RCR2 - 接收控制寄存器2 (偏移0x06) */
            BEGIN_MMR_REGISTER(rcr2, 0x2806)
                DECLARE_MMR_BIT(RPHASE, 15)          // [15] 接收相位
                DECLARE_MMR_BITS_FIELD(RFRLEN2, 7, 8) // [14-8] 帧长度2
                DECLARE_MMR_BITS_FIELD(RWDLEN2, 3, 5) // [7-5] 字长2
                DECLARE_MMR_BITS_FIELD(RCOMPAND, 2, 3) // [4-3] 压缩扩展模式
                DECLARE_MMR_BIT(RFIG, 2)             // [2] 接收帧忽略
                DECLARE_MMR_BITS_FIELD(RDATDLY, 2, 0) // [1-0] 接收数据延时
            END_MMR_REGISTER()

            /* RCR1 - 接收控制寄存器1 (偏移0x07) */
            BEGIN_MMR_REGISTER(rcr1, 0x2807)
                DECLARE_MMR_BITS_FIELD(RFRLEN1, 7, 8) // [14-8] 帧长度1
                DECLARE_MMR_BITS_FIELD(RWDLEN1, 3, 5) // [7-5] 字长1
            END_MMR_REGISTER()

            /* XCR2 - 发送控制寄存器2 (偏移0x08) */
            BEGIN_MMR_REGISTER(xcr2, 0x2808)
                DECLARE_MMR_BIT(XPHASE, 15)          // [15] 发送相位
                DECLARE_MMR_BITS_FIELD(XFRLEN2, 7, 8) // [14-8] 帧长度2
                DECLARE_MMR_BITS_FIELD(XWDLEN2, 3, 5) // [7-5] 字长2
                DECLARE_MMR_BITS_FIELD(XCOMPAND, 2, 3) // [4-3] 压缩扩展模式
                DECLARE_MMR_BIT(XFIG, 2)             // [2] 发送帧忽略
                DECLARE_MMR_BITS_FIELD(XDATDLY, 2, 0) // [1-0] 发送数据延时
            END_MMR_REGISTER()

            /* XCR1 - 发送控制寄存器1 (偏移0x09) */
            BEGIN_MMR_REGISTER(xcr1, 0x2809)
                DECLARE_MMR_BITS_FIELD(XFRLEN1, 7, 8) // [14-8] 帧长度1
                DECLARE_MMR_BITS_FIELD(XWDLEN1, 3, 5) // [7-5] 字长1
            END_MMR_REGISTER()

            //----------------------------------
            // 采样率生成器寄存器
            //----------------------------------
            /* SRGR2 - 采样率发生器寄存器2 (偏移0x0A) */
            BEGIN_MMR_REGISTER(srgr2, 0x280A)
                DECLARE_MMR_BIT(GSYNC, 15)           // [15] CLKG同步
                DECLARE_MMR_BIT(CLKSP, 14)           // [14] CLKS引脚极性
                DECLARE_MMR_BIT(CLKSM, 13)           // [13] 采样率发生器时钟源
                DECLARE_MMR_BIT(FSGM, 12)            // [12] 帧同步生成模式
                DECLARE_MMR_BITS_FIELD(FPER, 12, 0)  // [11-0] 帧周期
            END_MMR_REGISTER()

            /* SRGR1 - 采样率发生器寄存器1 (偏移0x0B) */
            BEGIN_MMR_REGISTER(srgr1, 0x280B)
                DECLARE_MMR_BITS_FIELD(FWID, 8, 8)   // [15-8] 帧宽度
                DECLARE_MMR_BITS_FIELD(CLKGDV, 8, 0) // [7-0] 时钟分频因子
            END_MMR_REGISTER()

            //----------------------------------
            // 多通道控制寄存器
            //----------------------------------
            /* RCR2 - 多通道控制寄存器2 (偏移0x0C) */
            BEGIN_MMR_REGISTER(mcr2, 0x280C)
                DECLARE_MMR_BIT(XMCME, 15)           // [15] 增强型发送多通道使能
                DECLARE_MMR_BITS_FIELD(XPBBLK, 2, 13) // [14-13] 发送分区B块
                DECLARE_MMR_BITS_FIELD(XPABLK, 2, 11) // [12-11] 发送分区A块
                DECLARE_MMR_BITS_FIELD(XCBLK, 5, 6)  // [10-6] 当前发送块
                DECLARE_MMR_BITS_FIELD(XMCM, 2, 4)   // [5-4] 发送多通道选择
            END_MMR_REGISTER()

            // MCR1 多通道控制寄存器1
            BEGIN_MMR_REGISTER(mcr1, 0x280D)
                DECLARE_MMR_BIT(RMCME, 15)        // [15] 接收多通道使能扩展
                DECLARE_MMR_BITS_FIELD(RPBBLK, 3, 12) // [14-12] 接收分区B块大小
                DECLARE_MMR_BITS_FIELD(RPABLK, 3, 8)  // [11-8]  接收分区A块大小
                DECLARE_MMR_BITS_FIELD(RCBLK, 3, 5)   // [7-5]   接收当前块
                DECLARE_MMR_BIT(XMCME, 4)         // [4]    发送多通道使能扩展
                DECLARE_MMR_BITS_FIELD(XPBBLK, 3, 1)  // [3-1]   发送分区B块大小
                DECLARE_MMR_BIT(XPABLK, 0)        // [0]    发送分区A块大小
            END_MMR_REGISTER()

            //----------------------------------
            // 增强型通道使能寄存器
            //----------------------------------
            DECLARE_MMR_REGISTER(rcera, 0x280E); // 接收通道使能寄存器A
            DECLARE_MMR_REGISTER(rcerb, 0x280F); // 接收通道使能寄存器B
            DECLARE_MMR_REGISTER(xcera, 0x2810); // 发送通道使能寄存器A
            DECLARE_MMR_REGISTER(xcerb, 0x2811); // 发送通道使能寄存器B

            //----------------------------------
            // 引脚控制寄存器
            //----------------------------------
            /* PCR - 引脚控制寄存器 (偏移0x12) */
            BEGIN_MMR_REGISTER(pcr, 0x2812)
                DECLARE_MMR_BIT(IDLE_EN, 14)         // [14] 空闲使能
                DECLARE_MMR_BIT(XIOEN, 13)           // [13] 发送通用IO模式
                DECLARE_MMR_BIT(RIOEN, 12)           // [12] 接收通用IO模式
                DECLARE_MMR_BIT(FSXM, 11)            // [11] 发送帧同步模式
                DECLARE_MMR_BIT(FSRM, 10)            // [10] 接收帧同步模式
                DECLARE_MMR_BIT(CLKXM, 9)            // [9] 发送时钟模式
                DECLARE_MMR_BIT(CLKRM, 8)            // [8] 接收时钟模式
                DECLARE_MMR_BIT(SCLKME, 7)           // [7] 二级时钟模式使能
                DECLARE_MMR_BIT(CLKS_STAT, 6)        // [6] CLKS引脚状态
                DECLARE_MMR_BIT(DX_STAT, 5)          // [5] DX引脚状态
                DECLARE_MMR_BIT(DR_STAT, 4)          // [4] DR引脚状态
                DECLARE_MMR_BIT(FSXP, 3)             // [3] 发送帧同步极性
                DECLARE_MMR_BIT(FSRP, 2)             // [2] 接收帧同步极性
                DECLARE_MMR_BIT(CLKXP, 1)            // [1] 发送时钟极性
                DECLARE_MMR_BIT(CLKRP, 0)            // [0] 接收时钟极性
            END_MMR_REGISTER()

            //----------------------------------
            // 扩展通道使能寄存器组
            //----------------------------------
            DECLARE_MMR_REGISTER(pcerc, 0x2813); // 接收分区C通道使能
            DECLARE_MMR_REGISTER(pcerd, 0x2814); // 接收分区D通道使能
            DECLARE_MMR_REGISTER(xcerc, 0x2815); // 发送分区C通道使能
            DECLARE_MMR_REGISTER(xcerd, 0x2816); // 发送分区D通道使能
            DECLARE_MMR_REGISTER(rcere, 0x2817); // 接收分区E通道使能
            DECLARE_MMR_REGISTER(rcerf, 0x2818); // 接收分区F通道使能
            DECLARE_MMR_REGISTER(xcere, 0x2819); // 发送分区E通道使能
            DECLARE_MMR_REGISTER(xcerf, 0x281A); // 发送分区F通道使能
            DECLARE_MMR_REGISTER(rcerg, 0x281B); // 接收分区G通道使能
            DECLARE_MMR_REGISTER(rcerh, 0x281C); // 接收分区H通道使能
            DECLARE_MMR_REGISTER(xcerg, 0x281D); // 发送分区G通道使能
            DECLARE_MMR_REGISTER(xcerh, 0x281E); // 发送分区H通道使能
        }

        namespace info
        {
            //------------------------------
            // 串口控制寄存器1 (SPCR1)
            //------------------------------
            DECLARE_ATTRIBUTE(SPCR1_MASK,
                              DLB = 0x8000, // 数字环回模式 (1: 使能环回)
                              RJUST = 0x6000, // 接收数据对齐方式：
                              RJUST_RIGHT = 0x0000, // 右对齐并符号扩展
                              RJUST_LEFT = 0x2000, // 左对齐并填充0

                              CLKSTP = 0x1800, // 时钟停止模式：
                              CLKSTP_DIS = 0x0000, // 禁用时钟停止模式
                              CLKSTP_NODELAY=0x1000, // 无延迟时钟停止
                              CLKSTP_DELAY = 0x1800, // 有延迟时钟停止

                              DXENA = 0x0080, // DX延迟使能 (1: 插入1位延迟)
                              ABIS = 0x0040, // ABIS模式选择 (1: 使能ABIS模式)
                              RINTM = 0x0030, // 接收中断模式：
                              RINTM_RRDY = 0x0000, // RRDY触发中断
                              RINTM_FRAME = 0x0010, // 帧结束触发中断

                              RSYNCERR = 0x0008, // 接收同步错误状态 (只读)
                              RFULL = 0x0004, // 接收移位寄存器满 (只读)
                              RRDY = 0x0002, // 接收就绪标志 (只读)
                              RRST = 0x0001 // 接收器复位 (0: 复位，1: 使能)
            )
            DECLARE_ATTRIBUTE(SPCR1_SHIFT,
                  RINTM_FRAME = 4, // 帧结束触发中断

                  RSYNCERR = 3, // 接收同步错误状态 (只读)
                  RFULL = 2, // 接收移位寄存器满 (只读)
                  RRDY = 1, // 接收就绪标志 (只读)
                  RRST = 0 // 接收器复位 (0: 复位，1: 使能)
)

            //------------------------------
            // 串口控制寄存器2 (SPCR2)
            //------------------------------
            DECLARE_ATTRIBUTE(SPCR2_MASK,
                              FREE = 0x0200, // 自由运行模式 (1: 仿真时继续运行)
                              SOFT = 0x0100, // 软停止模式 (1: 仿真时完成当前传输)
                              FRST = 0x0080, // 帧同步发生器复位 (0: 复位，1: 运行)
                              GRST = 0x0040, // 采样率发生器复位 (0: 复位，1: 运行)
                              XINTM = 0x0030, // 发送中断模式：
                              XINTM_XRDY = 0x0000, // XRDY触发中断
                              XINTM_FRAME = 0x0010, // 帧结束触发中断

                              XSYNCERR = 0x0008, // 发送同步错误状态 (只读)
                              XEMPTY = 0x0004, // 发送移位寄存器空 (只读)
                              XRDY = 0x0002, // 发送就绪标志 (只读)
                              XRST = 0x0001 // 发送器复位 (0: 复位，1: 使能)
            )

            DECLARE_ATTRIBUTE(SPCR2_SHIFT,
                              FREE = 9, // 自由运行模式 (1: 仿真时继续运行)
                              SOFT = 8, // 软停止模式 (1: 仿真时完成当前传输)
                              FRST = 7, // 帧同步发生器复位 (0: 复位，1: 运行)
                              GRST = 6, // 采样率发生器复位 (0: 复位，1: 运行)
                              XINTM = 0x0030, // 发送中断模式：
                              XINTM_XRDY = 0x0000, // XRDY触发中断
                              XINTM_FRAME = 4, // 帧结束触发中断

                              XSYNCERR = 3, // 发送同步错误状态 (只读)
                              XEMPTY = 2, // 发送移位寄存器空 (只读)
                              XRDY = 1, // 发送就绪标志 (只读)
                              XRST = 0 // 发送器复位 (0: 复位，1: 使能)
            )


            //------------------------------
            // 引脚控制寄存器 (PCR)
            //------------------------------
            DECLARE_ATTRIBUTE(PCR,
                              IDLE_EN = 0x4000, // 空闲状态使能 (1: CLKG/FSG进入低功耗)
                              XIOEN = 0x2000, // DX引脚GPIO模式 (1: GPIO，0: 串口)
                              RIOEN = 0x1000, // DR引脚GPIO模式 (1: GPIO，0: 串口)
                              FSXM = 0x0800, // 发送帧同步模式 (1: 内部生成)
                              FSRM = 0x0400, // 接收帧同步模式 (1: 内部生成)
                              CLKXM = 0x0200, // 发送时钟模式 (1: 内部生成)
                              CLKRM = 0x0100, // 接收时钟模式 (1: 内部生成)
                              SCLKME = 0x0080, // 采样时钟模式 (1: CLKR/CLKX，0: CLKS)
                              CLKS_STAT = 0x0040, // CLKS引脚状态 (只读)
                              DX_STAT = 0x0020, // DX引脚状态 (只读)
                              DR_STAT = 0x0010, // DR引脚状态 (只读)
                              FSXP = 0x0008, // 发送帧同步极性 (1: 下降沿有效)
                              FSRP = 0x0004, // 接收帧同步极性 (1: 下降沿有效)
                              CLKXP = 0x0002, // 发送时钟极性 (1: 下降沿采样)
                              CLKRP = 0x0001 // 接收时钟极性 (1: 下降沿采样)
            )

            //------------------------------
            // 接收配置寄存器 (RCR1/RCR2)
            //------------------------------
            DECLARE_ATTRIBUTE(RCR1, // 接收阶段1帧长度 (0-127个字)
                              // 接收阶段1字长：
                              RWDLEN1_8 = 0x0000, // 8位字长
                              RWDLEN1_12 = 0x0020, // 12位字长
                              RWDLEN1_16 = 0x0040, // 16位字长
                              RWDLEN1_20 = 0x0060, // 20位字长
                              RWDLEN1_24 = 0x0080, // 24位字长
                              RWDLEN1_32 = 0x00A0 // 32位字长
            )

            DECLARE_ATTRIBUTE(RCR2,
                              RPHASE_SINGLE = 0x0000, // 接收阶段数 (0: 单相，1: 双相)
                              RPHASE_DUAL = 0x8000,
                              RDATDLY_0 = 0x0000, // 0位延迟
                              RDATDLY_1 = 0x0001, // 1位延迟
                              RDATDLY_2 = 0x0002 // 2位延迟
            )

            //------------------------------
            // 发送配置寄存器 (XCR1/XCR2)
            //------------------------------
            DECLARE_ATTRIBUTE(XCR1,
                              XFRLEN1_1 = 0x0000, // 发送阶段1字长 (同RWDLEN1)
                              XWDLEN1_8 = 0x0000,
                              XWDLEN1_12 = 0x0020,
                              XWDLEN1_16 = 0x0040,
                              XWDLEN1_20 = 0x0060,
                              XWDLEN1_24 = 0x0080,
                              XWDLEN1_32 = 0x00a0,
            )

            DECLARE_ATTRIBUTE(XCR2,
                              XPHASE_SINGLE = 0x0000, // 发送阶段数 (0: 单相，1: 双相)
                              XPHASE_DUAL = 0x8000,
                              XDATDLY_0 = 0x0000,
                              XDATDLY_1 = 0x0001,
                              XDATDLY_2 = 0x0002,
            )

            //------------------------------
            // 采样率生成寄存器 (SRGR1/SRGR2)
            //------------------------------
            DECLARE_ATTRIBUTE(SRGR1,
                              FWID = 0xFF00, // 帧同步脉冲宽度 (CLKG周期数)
                              CLKGDV = 0x00FF // 时钟分频因子 (1-255分频)
            )

            DECLARE_ATTRIBUTE(SRGR2,
                              GSYNC = 0x8000, // 时钟同步 (1: CLKG与外部时钟同步)
                              CLKSP = 0x4000, // 时钟极性选择 (1: CLKS下降沿产生CLKG)
                              CLKSM = 0x2000, // 时钟源选择 (1: CPU时钟，0: CLKS引脚)
                              FSGM = 0x1000, // 帧同步模式 (1: 由采样率生成器产生)
                              FPER = 0x0FFF // 帧同步周期 (0-4095 CLKG周期)
            )
        }

        class Control
        {
        public:
            static void init(const bool receive_IT =false, const bool transmit_IT=false)
            {
                // McBSP0复位
                regs::spcr1::clear();
                regs::spcr2::clear();

                // 配置帧参数(16位，单相，无延迟)
                regs::xcr1::write(info::XCR1::XWDLEN1_16);
                regs::xcr2::write(info::XCR2::XPHASE_SINGLE | info::XCR2::XDATDLY_0);
                regs::rcr1::write(info::RCR1::RWDLEN1_16);
                regs::rcr2::write(info::RCR2::RPHASE_SINGLE | info::RCR2::RDATDLY_0);

                /// 使用帧同步会出问题
                // 禁止内部生成帧同步信号，配置为从模式使用FSX引脚的外部帧同步
                // 帧同步高电平有效，数据在CLKX时钟上升沿进行采样
                // regs::pcr::write(info::PCR::CLKXP);

                // 最小化极性配置
                regs::pcr::write(0); // 所有极性默认（上升沿有效，高电平有效）

                // 关键：启动采样率发生器！！！
                regs::spcr2::GRST::set();  // 启动采样率发生器
                systick::Delay::us(10); // 等待稳定

                // 设置接收中断模式为 "RRDY 触发中断" (RINTM = 00)
                regs::spcr1::RINTM::write_bits(0);

                //发送器摆脱复位  接收器使能
                regs::spcr1::or_mask(info::SPCR1_MASK::RRST);
                regs::spcr2::or_mask(info::SPCR2_MASK::XRST);

                if (receive_IT)
                    start_receiveIT();
                if (transmit_IT)
                    start_transmitIT();
            }

            static void start_receiveIT()
            {
                // 启动接收中断
                cpu::IER0::RINT0::set();
                cpu::DBIER0::RINT0::set();
                volatile uint16_t temp;
                read_data1(temp);// 必须先读取一次数据（重点在读drr寄存器），之后的中断才能正常触发
            }

            static void start_transmitIT()
            {
                // 启动接收中断
                cpu::IER1::XINT0::set();
                cpu::DBIER1::XINT0::set();
                write(0xFFFF, 0xFFFF);
            }

            static void disable()
            {
                // McBSP0复位
                regs::spcr1::clear();
                regs::spcr2::clear();
            }

            /**
             * 读取通道数据
             * @tparam T 数据类型，可为short或者volatile short
             * @param data_1 通道1数据
             * @param data_2 通道2数据
             * @note 此函数在调试时小心，调试时有可能导致调试窗口无法以图像的形式显示，重启即可。不能显示的表面原因是：Current CPU is null
             */
            template<typename T>
            static void read(T& data_1,T& data_2)
            {
                STATIC_ASSERT(sizeof(T)==sizeof(short),"data type is not short!");
                // 等待McBSP0准备好
                while (regs::spcr1::RRDY::read_bit_not()){}
                data_1 = regs::drr1::read();
                data_2 = regs::drr2::read();
            }


            // 读取第一个通道的数据
            template<typename T>
            static void read_data1(T &data_1)
            {
                STATIC_ASSERT(sizeof(T)==sizeof(short),"data type is not short!");
                // 等待McBSP0准备好
                while (regs::spcr1::RRDY::read_bit_not()){}
                data_1 = regs::drr1::read();
            }


            // 读取第一个通道的数据
            template<typename T>
            static void read_data1_IT(T &data_1)
            {
                STATIC_ASSERT(sizeof(T)==sizeof(short),"data type is not short!");
                // 等待McBSP0准备好
                if (regs::spcr1::RRDY::read_bit())
                    data_1 = regs::drr1::read();
            }

            static void write_IT(const uint16_t data_L, const uint16_t data_R)
            {
                if (regs::spcr2::XRDY::read_bit())
                {
                    regs::dxr1::write(data_L);
                    regs::dxr2::write(data_R);
                }
            }

            template<typename T>
            static void read_data2(T &data_2)
            {
                STATIC_ASSERT(sizeof(T)==sizeof(short),"data type is not short!");
                // 等待McBSP0准备好
                while (regs::spcr1::RRDY::read_bit_not()){}
                data_2 = regs::drr2::read();
            }



            static void write(const uint16_t data_L, const uint16_t data_R)
            {
                // 等待McBSP0准备好
                while (regs::spcr2::XRDY::read_bit_not()) {}//  此处应该使用XRDY
                regs::dxr1::write(data_L);
                regs::dxr2::write(data_R);
            }


        };
    }
} // namespace bsp::mcsp

#endif //ZQ_MCBSP_H
